package cn.weiron.fun.infrastructure;

import cn.weiron.fun.infrastructure.auth.Authority;
import cn.weiron.fun.infrastructure.dto.LoggedAccountDto;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Repository;

import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * <p>基础层：用户登录仓储接口实现，通过HTTP访问平台服务实现</p>
 *
 * @author 马强
 */
@Repository("accountLoginCacheRepositoryRedis")
public class AccountLoginRepositoryRedisImpl implements AccountLoginRepository {
    /**
     * 存储键名：账户索引Hash
     */
    private static final String accountHashKey = "care4u.assign.accounts.cache";

    /**
     * 存储键名：Token存储名前缀
     */
    private static final String tokenKeyPrefix = "WebRedisKey:token:";

    /**
     * Redis
     */
    private final StringRedisTemplate redisTemplate;

    /**
     * 向缓存中存储当前数据，并返回存储后的数据
     */
    @Override
    public Optional<LoggedAccountDto> store(Authority.Account account) {
        if (!(account instanceof LoggedAccountDto)) return Optional.empty();

        // 序列化
        LoggedAccountDto accountDto = (LoggedAccountDto) account;
        String json = "";
        try {
            json = LoggedAccountDto.Assembler.serializeValue(accountDto);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            return Optional.empty();
        }

        // 存储 token -> po
        redisTemplate.opsForValue().set(
                tokenKeyPrefix + accountDto.getToken(),
                json,
                3600*3L, TimeUnit.MINUTES
        );
        // 加入到当前登录账户索引中
        redisTemplate.boundHashOps(accountHashKey).put(accountDto.getUserId(), accountDto.getToken());

        return Optional.of(accountDto);
    }

    /**
     * @return 验证指定数据是否存在，存在则返回存在的数据；不存在则返回空
     */
    @Override
    public Optional<LoggedAccountDto> exist(String token) {
        String json = redisTemplate.boundValueOps(tokenKeyPrefix + token).get();
        if (json == null) return Optional.empty();

        try {
            //去除左右两侧的引号
            json=json.substring(json.indexOf("{"),json.lastIndexOf("}")+1)
                    .replace("\\","");
            return Optional.of(LoggedAccountDto.Assembler.deserializeValue(json));
        } catch (IOException e) {
            e.printStackTrace();
            return Optional.empty();
        }
    }

    /**
     * @return 验证指定数据是否存在，存在则返回存在的数据；不存在则返回空
     */
    @Override
    public Optional<LoggedAccountDto> exist(LoggedAccountDto loginDo) {
        String token = loginDo.getToken();

        //如果token为空，通过账户从账户索引缓存中获取
        if (token == null || token.isEmpty()) {
            String account = loginDo.getUserId();
            if (account == null || account.isEmpty()) return Optional.empty();

            token = (String) redisTemplate.boundHashOps(accountHashKey).get(account);
            if (token == null) return Optional.empty();
        }

        return exist(loginDo.getToken());
    }

    /**
     * @return 清除指定数据，存在则返回已清除的数据；不存在则返回空
     */
    @Override
    public Optional<LoggedAccountDto> clear(LoggedAccountDto loginDo) {
        Optional<LoggedAccountDto> accountLogin = exist(loginDo);
        accountLogin.ifPresent(account -> {
            redisTemplate.delete(tokenKeyPrefix + loginDo.getToken());
            redisTemplate.boundHashOps(accountHashKey).delete(account.getUserId());
        });
        return accountLogin;
    }

    public AccountLoginRepositoryRedisImpl(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }
}